package com.craigcmiller.cmtetris.ui;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.awt.Component;
import javax.swing.Timer;

import com.craigcmiller.cmtetris.core.Board;
import com.craigcmiller.cmtetris.core.Cell;


/**
 * Provides functionality shared by the swing and the applet versions of the game
 * @author craig
 */
public class SwingGraphics implements KeyListener, ActionListener
{
	private Component component;
	private int cellWidth, cellHeight;
	private int width, height, columns, rows;
	private Board board;
	private Timer updateTimer;
	private final Color LEVEL_TEXT_COLOR=new Color(180, 180, 245);
	private final Font LEVEL_TEXT_FONT=new Font("Times New Roman", Font.BOLD, 24);
	private boolean showGrid;
	
	
	public SwingGraphics(Component component, int width, int height, int columns, int rows, boolean showGrid)
	{
		this.component=component;
		this.width=width;
		this.height=height;
		this.columns=columns;
		this.rows=rows;
		this.showGrid=showGrid;
		
		this.component.setSize(width, height);
		
		board=new Board(columns, rows);
		
		// Start the update timer
		(updateTimer=new Timer(board.getTimeBetweenUpdates(), this)).start();
		
		component.addKeyListener(this);
	}
	
	
	/**
	 * Draw the tetris game board
	 */
	public void paint(Graphics gfx)
	{
		this.width=component.getWidth();
		this.height=component.getHeight();
		this.cellWidth=width/columns;
		this.cellHeight=height/rows;
		
		BufferedImage bgImg=new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_ARGB);
		
		Graphics bg=bgImg.getGraphics();

		bg.setColor(Color.WHITE);
		bg.fillRect(0, 0, component.getWidth(), component.getHeight());
		
		if (!board.getIsGameOver()) {
			// Draw the level text
			bg.setFont(LEVEL_TEXT_FONT);
			bg.setColor(LEVEL_TEXT_COLOR);
			bg.drawString("Level " + board.getLevel(), width/2-35, height/8);
			
			if (showGrid) {
				bg.setColor(Color.LIGHT_GRAY);
		
				// Draw the row separators
				for (int i=0; i<this.rows; i++)
					bg.drawLine(0, i*this.cellHeight, this.width, i*this.cellHeight);
		
				// Draw the column separators
				for (int i=0; i<this.columns; i++)
					bg.drawLine(i*this.cellWidth, 0, i*this.cellWidth, this.height);
			}
			
			for (int y=0; y<board.getHeight(); y++) {
				for (int x=0; x<board.getWidth(); x++) {
					Cell cell=board.getCellAt(x, y);
					
					if (cell.getCellState()==Cell.CellState.set || cell.getCellState()==Cell.CellState.imaterial) {
						bg.setColor(cell.getCellColor());
						
						bg.fill3DRect(x*cellWidth, y*cellHeight, cellWidth, cellHeight, true);
					}
				}
			}
		} else {
			bg.setColor(new Color(245, 62, 76));
			bg.setFont(new Font("Times New Roman", Font.BOLD, 32));
			
			bg.drawString("Game Over!", this.width/2-80, this.height/2-20);
			
			bg.setColor(new Color(175, 175, 240));
			bg.setFont(new Font("Times New Roman", Font.BOLD, 18));
			bg.drawString("Score: " + board.getScore(), this.width/2-35, this.height/2+5);
		}

		gfx.drawImage(bgImg, 0, 0, null);
		
		//System.out.println(board);
	}
	
	
	public void keyTyped(KeyEvent k)
	{
	}
	
	
	public void keyReleased(KeyEvent k)
	{
	}
	
	
	/**
	 * Handle key presses
	 */
	public void keyPressed(KeyEvent k)
	{
		switch (k.getKeyCode()) {
			case 32: // Spacebar
				board.update();
				break;
			case 37: // Left arrow
				board.getActiveBlock().moveLeft();
				break;
			case 39: // Right arrow
				board.getActiveBlock().moveRight();
				break;
			case 38: // Up arrow
				board.getActiveBlock().rotate();
				break;
			case 40: // Down arrow
				board.getActiveBlock().moveDown();
				break;
			default:
				System.out.println("Key code: " + (int)k.getKeyCode());
		}
		
		component.repaint();
	}
	
	
	public void actionPerformed(ActionEvent ae)
	{
		if (ae.getSource()==this.updateTimer) {
			board.update();
			
			// Update the timer
			if (!board.getIsGameOver()) updateTimer.setDelay(board.getTimeBetweenUpdates());
			else updateTimer.stop();
			
			component.repaint();
		}
	}
}
